package com.mc.fastkit.widget

import androidx.annotation.CallSuper
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.withStateAtLeast
import com.mc.fastkit.ext.cast
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlin.coroutines.EmptyCoroutineContext

/**
 * Flow实现的事件总线
 * @author: MasterChan
 * @date: 2025-08-21 09:26
 */
object FlowBus {

    private val events = mutableMapOf<String, Event<*>>()
    private val stickyEvents = mutableMapOf<String, StickyEvent<*>>()

    fun <T> with(key: String): Event<T> {
        if (events[key] == null) {
            events[key] = Event<T>(key)
        }
        return events[key]!!.cast()
    }

    fun <T> withSticky(key: String): StickyEvent<T> {
        if (stickyEvents[key] == null) {
            stickyEvents[key] = StickyEvent<T>(key)
        }
        return stickyEvents[key]!!.cast()
    }

    abstract class AbsEvent<T>() {
        protected abstract val flow: MutableSharedFlow<T>
        protected abstract val key: String
        protected val jobMap by lazy { mutableMapOf<Int, Job>() }

        /**
         * 发送事件，自行处理生命周期
         */
        suspend fun send(event: T) {
            withContext(Dispatchers.IO) {
                flow.emit(event)
            }
        }

        /**
         * 发送事件，使用全局协程
         * @param event
         */
        fun post(event: T) {
            CoroutineScope(EmptyCoroutineContext).launch(Dispatchers.IO) {
                flow.emit(event)
            }
        }

        /**
         * 发送事件，使用给定的生命周期
         *
         * @param owner LifecycleOwner
         * @param event 事件
         */
        fun post(owner: LifecycleOwner, event: T) {
            owner.lifecycleScope.launch(Dispatchers.IO) {
                flow.emit(event)
            }
        }

        /**
         * 在主线程中收集事件，不受生命周期影响，将一直接收事件
         *
         * @param owner LifecycleOwner
         * @param action 事件
         */
        fun collect(owner: LifecycleOwner, action: suspend AbsEvent<T>.(T) -> Unit) {
            listenLifecycle(owner)
            owner.lifecycleScope.launch(Dispatchers.Main) {
                flow.collect {
                    action.invoke(this@AbsEvent, it)
                }
            }
        }

        /**
         * 在主线程中收集事件，受生命周期影响，在[minState]之前收到事件将会挂起直到[minState]再恢复
         *
         * @param owner LifecycleOwner
         * @param minState 最小生命周期状态
         * @param action 事件
         */
        fun observe(
            owner: LifecycleOwner,
            minState: Lifecycle.State = Lifecycle.State.RESUMED,
            action: AbsEvent<T>.(T) -> Unit
        ) {
            listenLifecycle(owner)
            owner.lifecycleScope.launch(Dispatchers.Main) {
                flow.collect {
                    jobMap[action.hashCode()]?.cancel()
                    jobMap[action.hashCode()] = launch {
                        owner.lifecycle.withStateAtLeast(minState) {
                            action.invoke(this@AbsEvent, it)
                        }
                    }
                }
            }
        }

        /**
         * 移除[key]对应的事件，移除后未重新订阅时，将不会收到后续事件
         */
        @CallSuper
        open fun removeEvent() {
            jobMap.forEach { it.value.cancel() }
            jobMap.clear()
        }

        private fun listenLifecycle(owner: LifecycleOwner) {
            owner.lifecycle.addObserver(object : DefaultLifecycleObserver {
                override fun onDestroy(owner: LifecycleOwner) {
                    if (flow.subscriptionCount.value <= 0) {
                        removeEvent()
                    }
                }
            })
        }
    }

    class Event<T>(override val key: String) : AbsEvent<T>() {

        override val flow = MutableSharedFlow<T>(0, 1, BufferOverflow.DROP_OLDEST)

        override fun removeEvent() {
            super.removeEvent()
            events.remove(key)
        }
    }

    class StickyEvent<T>(override val key: String) : AbsEvent<T>() {

        override val flow = MutableSharedFlow<T>(1, 1, BufferOverflow.DROP_OLDEST)

        override fun removeEvent() {
            super.removeEvent()
            stickyEvents.remove(key)
        }
    }
}